package com.rio.helper.file;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

/**
 * 多线程下载任务
 * 
 * @author rio.lv
 * 
 */
public class DownLoadTask {

	private String url;
	private File target;
	private int tnum;
	private DownloadListener listener;
	private int total;
	private int current = 0;
	private int complete = 0;
	private boolean crash = false;
	private boolean ready = false;

	public DownLoadTask(String url, File target, int tnum,
			DownloadListener listener) {
		super();
		this.url = url;
		this.target = target;
		this.tnum = tnum;
		this.listener = listener;
		start();
	}

	public DownLoadTask(String url, File target, int total, int tnum,
			DownloadListener listener) {
		super();
		this.url = url;
		this.target = target;
		this.tnum = tnum;
		this.listener = listener;
		this.total = total;
		start();
	}

	public void stop() {
		crash = true;
		if (target != null) {
			target.delete();
		}
		destory();
	}

	private void start() {
		try {
			createFile();
			final int block = (total + tnum - 1) / tnum;// 每个线程下载的快大小
			for (int i = 0; i < tnum; i++) {
				final int a = i;
				new Thread(new Runnable() {
					int start = block * a;// 开始位置
					int end = block * (a + 1) - 1;// 结束位置

					@Override
					public void run() {
						HttpURLConnection conn2 = null;// http连接
						RandomAccessFile accessFile2 = null;
						InputStream in = null;// 从http连接拿到的流
						try {
							URL ul = new URL(url);
							conn2 = (HttpURLConnection) ul.openConnection();
							conn2.setConnectTimeout(2000);// 请求超时时间
							conn2.setRequestMethod("GET");
							// TODO Auto-generated method stub
							conn2.setRequestProperty("Range", "bytes=" + start
									+ "-" + end + "");// 设置一般请求属性 范围
							in = conn2.getInputStream();
							int statusCode = conn2.getResponseCode();
							if (statusCode >= 200 && statusCode < 300) {
								byte[] data = new byte[1024];
								int len = 0;
								accessFile2 = new RandomAccessFile(target,
										"rwd");
								accessFile2.seek(start);
								while ((len = in.read(data)) != -1 && !crash) {
									accessFile2.write(data, 0, len);
									current += len;
									if (listener != null) {
										if (!ready) {
											ready = true;
											listener.onReady();
										}
										listener.onBytesCopied(current, total);
									}
								}
							} else {
								crash = true;
							}
							complete++;
						} catch (IOException e) {
							crash = true;
							if (listener != null) {
								listener.onFail(e, target, current);
							}
						} finally {
							try {
								if (accessFile2 != null)
									accessFile2.close();
								if (in != null)
									in.close();
								if (complete == tnum && listener != null) {
									if(!crash)listener.onComplete(url, target);
									destory();
								}
							} catch (IOException e) {
								crash = true;
								if (listener != null) {
									listener.onFail(e, target, current);
								}
							}

						}
					}

				}).start();

			}

		} catch (Exception e) {
			if (listener != null) {
				listener.onFail(e, target, current);
			}
		}

	}

	private void createFile() throws FileNotFoundException,
			MalformedURLException, IOException, ProtocolException {
		// 要写入的文件
		RandomAccessFile accessFile = new RandomAccessFile(target, "rwd");// 建立随机访问
		if (total <= 0) {
			URL ul = new URL(url);
			HttpURLConnection conn = (HttpURLConnection) ul.openConnection();
			conn.setConnectTimeout(2000);// 请求超时时间
			conn.setRequestMethod("GET");
			total = conn.getContentLength();// 文件长度
		}
		accessFile.setLength(total);
		accessFile.close();
	}

	private void destory() {
		target = null;
		url = null;
		listener = null;
	}

	/** Listener and controller for copy process */
	public interface DownloadListener {
		/**
		 * @param current
		 *            Loaded bytes
		 * @param total
		 *            Total bytes for loading
		 * @return <b>true</b> - if copying should be continued; <b>false</b> -
		 *         if copying should be interrupted
		 */
		void onBytesCopied(int current, int total);

		/**
		 * @param e
		 * @param target
		 */
		void onFail(Exception e, File target, int current);

		/**
		 * @param url
		 * @param target
		 */
		void onComplete(String url, File target);

		void onReady();

	}
}
